<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no" />
  <title>Birds Flying</title>
  <style>
    *{      
      -webkit-touch-callout: auto; /* prevent callout to copy image, etc when tap to hold */      
      -webkit-text-size-adjust: none; /* prevent webkit from resizing text to fit */      
      -webkit-tap-highlight-color: rgba(0,0,0,0); /* make transparent link selection, adjust last value opacity 0 to 1.0 */       
      -webkit-user-select:none;
    }  
    html,body {
      width: 100%;
      height: 100%;
      padding: 0;
      margin: 0;
      max-width: 500px;
    }
    #paper {
      position: relative;
      overflow: hidden;
      width: 100%;
      padding-top: 100%;
      height: 0px;
    }
  </style>
</head>
<body>
  <div>fps: <span id="fps">--</span> | sprites: <span id="spriteCount">1</span></div>
  <div id="paper"></div>
  
  <script src="https://s2.ssl.qhres.com/!87edaa34/animator-0.3.1.min.js"></script>
  <script src="https://s0.ssl.qhres.com/!cfaa644c/spritejs.min.js"></script>
  
  <script>
  const birdsJsonUrl = 'https://s5.ssl.qhres.com/static/5f6911b7b91c88da.json'
  const birdsRes = 'https://p.ssl.qhimg.com/d/inn/c886d09f/birds.png'

  ;(async function(){
    const paper = spritejs.Paper2D('#paper')
    paper.setResolution(800, 800) // 设置 Paper 的实际分辨率
    
    const cacheMap = new Map()
    window.cacheMap = cacheMap

    class Bird extends spritejs.Sprite {
      constructor(){
        super('bird1.png')
      }
      //共用缓存，提高性能
      get cache() {
        const key = JSON.stringify(this.textures) + this.attr('scale')
        if(cacheMap.has(key)) {
          return cacheMap.get(key)
        }      
      }
      set cache(context) {
        if(context == null){
          // cacheMap.clear()
          return
        }
        const key = JSON.stringify(this.textures) + this.attr('scale')

        if(!cacheMap.has(key)) {
          cacheMap.set(key, context)
        }
      }      
    }

    await paper.preload(
      [birdsRes, birdsJsonUrl]   // 预加载资源，支持雪碧图
    )  
    
    const bglayer = paper.layer('bg'),  // 背景层
          // 前景层
          // 不代理事件，提升性能
          fglayer = paper.layer('fg', {
                handleEvent: false,
                evaluateFPS: true,
                renderMode: 'repaintAll',
          })   
    
    const axisZero = [400, 400]
    const circle = new spritejs.Sprite()
    
    circle.attr({
      anchor: [0.5, 0.5],
      size: [800, 800],
      pos: axisZero,
      bgcolor: '#139',
      opacity: 0.5,
      borderRadius: 400,
    })
    
    bglayer.appendChild(circle)
    
    function pointAdd(p1, p2 = [0, 0]){
      return [p1[0] + p2[0], p1[1] + p2[1]].map(Math.round)
    }
    
    function pointSub(p1, p2 = [0, 0]){
      return [p1[0] - p2[0], p1[1] - p2[1]].map(Math.round)
    }
    
    function sleep(time){
      return new Promise(resolve => setTimeout(resolve, time))
    }
    
    async function randomAnimate(bird){
      const birdPoint = bird.attr('pos')
      const randomArc = Math.random() * 2 * Math.PI
      const randomPoint = pointAdd([350 * Math.cos(randomArc), 
                                    350 * Math.sin(randomArc)], axisZero)
      
      const dist = pointSub(randomPoint, birdPoint)
      const distance = Math.round(Math.sqrt(dist[0] * dist[0] + dist[1] * dist[1]))
      const flip = dist[0] < 0 ? -1 : 1
      const duration = 5 * distance + 100

      bird.attr('scale', [flip, 1]) //scale 放在外面，触发缓存

      const anim = new Animator(duration, function(p){
        const pos = pointAdd(birdPoint, [p * dist[0], p * dist[1]])
        if(isNaN(pos[0]) || isNaN(pos[1])){
          console.log('p', duration, p)
        }
        bird.attr({
          pos
        })
      })

      await anim.animate()
      await sleep(500)
    }

    let birdCount = 0
    async function addBird(){
      spriteCount.innerHTML = ++birdCount
      const bird = new Bird()

      bird.attr({
        anchor: [0.5, 0.5],
        pos: axisZero,
        transform: {
          rotate: 0,
        },
        size: [86, 60],
      })
      window.bird = bird

      fglayer.appendChild(bird)
      
      let idx = 0
      setInterval(() => {
        bird.textures = [`bird${++idx % 3 + 1}.png`]
      }, 100)
      window.bird = bird
      //noprotect
      do{
        await randomAnimate(bird)
      }while(1) 
    }

    addBird()

    circle.on('click', evt => {
      addBird()
    })
    let timer = setInterval(() => {
      if(birdCount < 500) addBird()
      else clearInterval(timer)
    }, 100)
    //显示 fps ，注意，因为本框架采用的是非定时渲染，即只有 sprite 有更新时才渲染
    //所以所有精灵不运动的时候 fps 也会降下来
    setInterval(() => {
      fps.innerHTML = fglayer.fps
    }, 1000)
    window.fglayer = fglayer
    window.paper = paper
  })()
  </script>
</body>
</html>